export interface IBoxCoord {
    boxIndex: number;
    cellIndex: number
}

export interface IRowColCoord {
    rowIndex: number;
    colIndex: number
}

/*
* 宫坐标系的工具
* */
const boxToolkit = {
    convertToBoxIndex(rowIndex: number, colIndex: number): IBoxCoord {
        return {
            boxIndex: Math.floor(rowIndex / 3) * 3 + Math.floor(colIndex / 3),
            cellIndex: rowIndex % 3 * 3 + colIndex % 3
        }
    },
    convertFromBoxIndex(boxIndex: number, cellIndex: number): IRowColCoord {
        return {
            rowIndex: Math.floor(boxIndex / 3) * 3 + Math.floor(cellIndex / 3),
            colIndex: boxIndex % 3 * 3 + cellIndex % 3
        }
    },
    // 获取 box 的数据
    getBoxCells(boxIndex: number, matrix: number[][]): number[] {
        const startRowIndex = Math.floor(boxIndex / 3) * 3;
        const startColIndex = boxIndex % 3 * 3;
        const result = [];
        for (let cellIndex = 0; cellIndex < 9; cellIndex++) {
            const rowIndex = startRowIndex + Math.floor(cellIndex / 3);
            const colIndex = startColIndex + cellIndex % 3;
            result.push(matrix[rowIndex][colIndex])
        }
        return result
    }
};


/*
* 矩阵 和 数组 相关的工具
* */
class matrixToolkit {
    static makeRow(): number[];
    static makeRow<T>(v: T): T[];
    static makeRow(v: any = 0): any[] {
        const array = new Array(9);
        array.fill(v);
        return array
    }

    static makeMatrix(): number[][];
    static makeMatrix<T>(v: T): T[];
    static makeMatrix(v: any = 0): any[][] {
        // const array = new Array(9);
        // array.fill(makeRow(v));
        // return array
        return Array.from({length: 9}, () => this.makeRow(v))
    }

// 生成数独数据结构测试
// const a = makeMatrix();
// a[0][1] = 2;
// console.log(a)

// 随机算法  Fisher-Yates 洗牌算法
    static shuffle<T>(array: T[]): T[] {
        const endIndex = array.length - 2;
        for (let i = 0; i <= endIndex; i++) {
            const j = i + Math.floor(Math.random() * (array.length - i));
            // es6 解构，进行数据交换
            [array[i], array[j]] = [array[j], array[i]]
        }
        return array
    }

    // 检查指定位置是否可以填写 n
    static checkFillAble(matrix: number[][], n: number, rowIndex: number, colIndex: number): boolean {
        const row = matrix[rowIndex];
        // const column = [[matrix[0][colIndex]],[matrix[1][colIndex]],[matrix[2][colIndex]] ... ]
        const column = this.makeRow().map((v, i) => matrix[i][colIndex]);
        const {boxIndex} = boxToolkit.convertToBoxIndex(rowIndex, colIndex);
        const box = boxToolkit.getBoxCells(boxIndex, matrix);
        // 判断里面数据是否完整
        for (let i = 0; i < 9; i++) {
            if (row[i] === n || column[i] === n || box[i] === n) {
                return false
            }
        }
        return true;
    }
}


// module.exports = class Toolkit {
export class Toolkit {            // ts 语法
    static get matrix(): typeof matrixToolkit {
        return matrixToolkit
    }

    static get box() {
        return boxToolkit
    }
}

export default Toolkit;
